import itertools


# 1. 加载数据集
def load_data(filename):
    """
    从本地文件加载数据集，每行是一个数据样本。
    假设数据为逗号分隔，特征和标签都在一行中。
    """
    data = []
    with open(filename, 'r') as file:
        for line in file.readlines():
            line = line.strip()
            # 分割特征和标签
            items = line.split(',')
            features = items[:-1]  # 特征列
            label = items[-1]  # 标签列
            data.append(set(features))
    return data


# 2. 生成候选1项集
def create_c1(data):
    """
    从数据集中生成候选1项集（即每个单独的项）。
    """
    c1 = set()
    for transaction in data:
        for item in transaction:
            c1.add(frozenset([item]))  # 使用frozenset表示不可变项集
    return c1


# 3. 计算支持度
def calculate_support(data, candidate):
    """
    计算候选项集的支持度（频率），返回支持度字典。
    """
    total_transactions = len(data)
    item_count = {}

    for transaction in data:
        for item in candidate:
            if item.issubset(transaction):  # 子集关系
                if item not in item_count:
                    item_count[item] = 0
                item_count[item] += 1

    # 计算支持度
    item_support = {}
    for item, count in item_count.items():
        item_support[item] = count / total_transactions
    return item_support


# 4. 筛选频繁项集
def filter_frequent_itemsets(item_support, min_support):
    """
    根据最小支持度筛选出频繁项集。
    """
    frequent_itemsets = {}
    for item, support in item_support.items():
        if support >= min_support:
            frequent_itemsets[item] = support
    return frequent_itemsets


# 5. 生成候选k项集
def apriori_gen(frequent_itemsets, k):
    """
    根据频繁k-1项集生成候选k项集。
    """
    candidates = set()
    frequent_itemsets_list = list(frequent_itemsets.keys())

    for i in range(len(frequent_itemsets_list)):
        for j in range(i + 1, len(frequent_itemsets_list)):
            # 尝试合并两个频繁项集，合并后的项集大小为k
            itemset1 = frequent_itemsets_list[i]
            itemset2 = frequent_itemsets_list[j]
            union_set = itemset1 | itemset2
            # 合并的项集大小必须为k
            if len(union_set) == k:
                candidates.add(union_set)
    return candidates


# 6. Apriori主算法
def apriori(data, min_support):
    """
    实现Apriori算法，返回频繁项集。
    """
    c1 = create_c1(data)  # 生成候选1项集
    frequent_itemsets = {}
    k = 1

    while True:
        # 计算候选项集的支持度
        item_support = calculate_support(data, c1)

        # 获取频繁项集
        frequent_k_itemsets = filter_frequent_itemsets(item_support, min_support)
        if not frequent_k_itemsets:
            break

        # 将频繁项集保存
        frequent_itemsets[k] = frequent_k_itemsets

        # 生成候选k+1项集
        c1 = apriori_gen(frequent_k_itemsets, k + 1)
        k += 1

    return frequent_itemsets


# 7. 主程序
if __name__ == "__main__":
    # 设置文件名
    filename = "C:\\Users\\li\\Desktop\\机器学习\\iris\\iris.data"

    # 加载数据
    data = load_data(filename)

    # 设置最小支持度
    min_support = 0.05  # 设定最小支持度为5%

    # 运行Apriori算法
    frequent_itemsets = apriori(data, min_support)

    # 输出频繁项集
    print("频繁项集：")
    for k, itemsets in frequent_itemsets.items():
        print(f"{k}-项集: {itemsets}")
